1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package com.google.common.cache;
16
17 import com.google.common.base.Function;
18 import com.google.common.base.MoreObjects;
19 import com.google.common.base.Objects;
20 import com.google.common.base.Optional;
21 import com.google.common.base.Preconditions;
22 import com.google.common.cache.LocalCache.Strength;
23 import com.google.common.collect.Iterables;
24 import com.google.common.collect.Lists;
25 import com.google.common.collect.Sets;
26
27 import java.util.List;
28 import java.util.Set;
29 import java.util.concurrent.TimeUnit;
30
31 import javax.annotation.Nullable;
32
33
34
35
36
37
38
39 class CacheBuilderFactory {
40
41
42 private Set<Integer> concurrencyLevels = Sets.newHashSet((Integer) null);
43 private Set<Integer> initialCapacities = Sets.newHashSet((Integer) null);
44 private Set<Integer> maximumSizes = Sets.newHashSet((Integer) null);
45 private Set<DurationSpec> expireAfterWrites = Sets.newHashSet((DurationSpec) null);
46 private Set<DurationSpec> expireAfterAccesses = Sets.newHashSet((DurationSpec) null);
47 private Set<DurationSpec> refreshes = Sets.newHashSet((DurationSpec) null);
48 private Set<Strength> keyStrengths = Sets.newHashSet((Strength) null);
49 private Set<Strength> valueStrengths = Sets.newHashSet((Strength) null);
50
51 CacheBuilderFactory withConcurrencyLevels(Set<Integer> concurrencyLevels) {
52 this.concurrencyLevels = Sets.newLinkedHashSet(concurrencyLevels);
53 return this;
54 }
55
56 CacheBuilderFactory withInitialCapacities(Set<Integer> initialCapacities) {
57 this.initialCapacities = Sets.newLinkedHashSet(initialCapacities);
58 return this;
59 }
60
61 CacheBuilderFactory withMaximumSizes(Set<Integer> maximumSizes) {
62 this.maximumSizes = Sets.newLinkedHashSet(maximumSizes);
63 return this;
64 }
65
66 CacheBuilderFactory withExpireAfterWrites(Set<DurationSpec> durations) {
67 this.expireAfterWrites = Sets.newLinkedHashSet(durations);
68 return this;
69 }
70
71 CacheBuilderFactory withExpireAfterAccesses(Set<DurationSpec> durations) {
72 this.expireAfterAccesses = Sets.newLinkedHashSet(durations);
73 return this;
74 }
75
76 CacheBuilderFactory withRefreshes(Set<DurationSpec> durations) {
77 this.refreshes = Sets.newLinkedHashSet(durations);
78 return this;
79 }
80
81 CacheBuilderFactory withKeyStrengths(Set<Strength> keyStrengths) {
82 this.keyStrengths = Sets.newLinkedHashSet(keyStrengths);
83 Preconditions.checkArgument(!this.keyStrengths.contains(Strength.SOFT));
84 return this;
85 }
86
87 CacheBuilderFactory withValueStrengths(Set<Strength> valueStrengths) {
88 this.valueStrengths = Sets.newLinkedHashSet(valueStrengths);
89 return this;
90 }
91
92 Iterable<CacheBuilder<Object, Object>> buildAllPermutations() {
93 @SuppressWarnings("unchecked")
94 Iterable<List<Object>> combinations = buildCartesianProduct(concurrencyLevels,
95 initialCapacities, maximumSizes, expireAfterWrites, expireAfterAccesses, refreshes,
96 keyStrengths, valueStrengths);
97 return Iterables.transform(combinations,
98 new Function<List<Object>, CacheBuilder<Object, Object>>() {
99 @Override public CacheBuilder<Object, Object> apply(List<Object> combination) {
100 return createCacheBuilder(
101 (Integer) combination.get(0),
102 (Integer) combination.get(1),
103 (Integer) combination.get(2),
104 (DurationSpec) combination.get(3),
105 (DurationSpec) combination.get(4),
106 (DurationSpec) combination.get(5),
107 (Strength) combination.get(6),
108 (Strength) combination.get(7));
109 }
110 });
111 }
112
113 private static final Function<Object, Optional<?>> NULLABLE_TO_OPTIONAL =
114 new Function<Object, Optional<?>>() {
115 @Override public Optional<?> apply(@Nullable Object obj) {
116 return Optional.fromNullable(obj);
117 }
118 };
119
120 private static final Function<Optional<?>, Object> OPTIONAL_TO_NULLABLE =
121 new Function<Optional<?>, Object>() {
122 @Override public Object apply(Optional<?> optional) {
123 return optional.orNull();
124 }
125 };
126
127
128
129
130
131
132
133
134 private Iterable<List<Object>> buildCartesianProduct(Set<?>... sets) {
135 List<Set<Optional<?>>> optionalSets = Lists.newArrayListWithExpectedSize(sets.length);
136 for (Set<?> set : sets) {
137 Set<Optional<?>> optionalSet =
138 Sets.newLinkedHashSet(Iterables.transform(set, NULLABLE_TO_OPTIONAL));
139 optionalSets.add(optionalSet);
140 }
141 Set<List<Optional<?>>> cartesianProduct = Sets.cartesianProduct(optionalSets);
142 return Iterables.transform(cartesianProduct,
143 new Function<List<Optional<?>>, List<Object>>() {
144 @Override public List<Object> apply(List<Optional<?>> objs) {
145 return Lists.transform(objs, OPTIONAL_TO_NULLABLE);
146 }
147 });
148 }
149
150 private CacheBuilder<Object, Object> createCacheBuilder(
151 Integer concurrencyLevel, Integer initialCapacity, Integer maximumSize,
152 DurationSpec expireAfterWrite, DurationSpec expireAfterAccess, DurationSpec refresh,
153 Strength keyStrength, Strength valueStrength) {
154
155 CacheBuilder<Object, Object> builder = CacheBuilder.newBuilder();
156 if (concurrencyLevel != null) {
157 builder.concurrencyLevel(concurrencyLevel);
158 }
159 if (initialCapacity != null) {
160 builder.initialCapacity(initialCapacity);
161 }
162 if (maximumSize != null) {
163 builder.maximumSize(maximumSize);
164 }
165 if (expireAfterWrite != null) {
166 builder.expireAfterWrite(expireAfterWrite.duration, expireAfterWrite.unit);
167 }
168 if (expireAfterAccess != null) {
169 builder.expireAfterAccess(expireAfterAccess.duration, expireAfterAccess.unit);
170 }
171 if (refresh != null) {
172 builder.refreshAfterWrite(refresh.duration, refresh.unit);
173 }
174 if (keyStrength != null) {
175 builder.setKeyStrength(keyStrength);
176 }
177 if (valueStrength != null) {
178 builder.setValueStrength(valueStrength);
179 }
180 return builder;
181 }
182
183 static class DurationSpec {
184 private final long duration;
185 private final TimeUnit unit;
186
187 private DurationSpec(long duration, TimeUnit unit) {
188 this.duration = duration;
189 this.unit = unit;
190 }
191
192 public static DurationSpec of(long duration, TimeUnit unit) {
193 return new DurationSpec(duration, unit);
194 }
195
196 @Override
197 public int hashCode() {
198 return Objects.hashCode(duration, unit);
199 }
200
201 @Override
202 public boolean equals(Object o) {
203 if (o instanceof DurationSpec) {
204 DurationSpec that = (DurationSpec) o;
205 return unit.toNanos(duration) == that.unit.toNanos(that.duration);
206 }
207 return false;
208 }
209
210 @Override
211 public String toString() {
212 return MoreObjects.toStringHelper(this)
213 .add("duration", duration)
214 .add("unit", unit)
215 .toString();
216 }
217 }
218 }